﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using Xamarin.Essentials;

namespace GyroscopeSample.ViewModels {
    public class MainPageViewModel : ViewModelBase {
        // ******** 构造函数
        public MainPageViewModel() { }

        // ******** 绑定属性

        /// <summary>
        /// 加速计X
        /// </summary>
        public double AccelerometerX
        {
            get => _accelerometerX;
            set => Set(nameof(AccelerometerX), ref _accelerometerX, value);
        }

        /// <summary>
        /// 加速计X
        /// </summary>
        private double _accelerometerX;

        /// <summary>
        /// 加速计MinX
        /// </summary>
        public double AccelerometerMinX {
            get => _accelerometerMinX;
            set => Set(nameof(AccelerometerMinX), ref _accelerometerMinX, value);
        }

        /// <summary>
        /// 加速计MinX
        /// </summary>
        private double _accelerometerMinX;

        /// <summary>
        /// 加速计MaxX
        /// </summary>
        public double AccelerometerMaxX
        {
            get => _accelerometerMaxX;
            set => Set(nameof(AccelerometerMaxX), ref _accelerometerMaxX, value);
        }

        /// <summary>
        /// 加速计MaxX
        /// </summary>
        private double _accelerometerMaxX;

        /// <summary>
        /// 加速计Y
        /// </summary>
        public double AccelerometerY
        {
            get => _accelerometerY;
            set => Set(nameof(AccelerometerY), ref _accelerometerY, value);
        }

        /// <summary>
        /// 加速计Y
        /// </summary>
        private double _accelerometerY;

        /// <summary>
        /// 加速计MinY
        /// </summary>
        public double AccelerometerMinY
        {
            get => _accelerometerMinY;
            set => Set(nameof(AccelerometerMinY), ref _accelerometerMinY, value);
        }

        /// <summary>
        /// 加速计MinY
        /// </summary>
        private double _accelerometerMinY;

        /// <summary>
        /// 加速计MaxY
        /// </summary>
        public double AccelerometerMaxY
        {
            get => _accelerometerMaxY;
            set => Set(nameof(AccelerometerMaxY), ref _accelerometerMaxY, value);
        }

        /// <summary>
        /// 加速计MaxY
        /// </summary>
        private double _accelerometerMaxY;

        /// <summary>
        /// 加速计Z
        /// </summary>
        public double AccelerometerZ
        {
            get => _accelerometerZ;
            set => Set(nameof(AccelerometerZ), ref _accelerometerZ, value);
        }

        /// <summary>
        /// 加速计Z
        /// </summary>
        private double _accelerometerZ;

        /// <summary>
        /// 加速计MinZ
        /// </summary>
        public double AccelerometerMinZ
        {
            get => _accelerometerMinZ;
            set => Set(nameof(AccelerometerMinZ), ref _accelerometerMinZ, value);
        }

        /// <summary>
        /// 加速计MinZ
        /// </summary>
        private double _accelerometerMinZ;

        /// <summary>
        /// 加速计MaxZ
        /// </summary>
        public double AccelerometerMaxZ
        {
            get => _accelerometerMaxZ;
            set => Set(nameof(AccelerometerMaxZ), ref _accelerometerMaxZ, value);
        }

        /// <summary>
        /// 加速计MaxZ
        /// </summary>
        private double _accelerometerMaxZ;

        /// <summary>
        /// 陀螺仪X
        /// </summary>
        public double GyroscopeX
        {
            get => _gyroscopeX;
            set => Set(nameof(GyroscopeX), ref _gyroscopeX, value);
        }

        /// <summary>
        /// 陀螺仪X
        /// </summary>
        private double _gyroscopeX;

        /// <summary>
        /// 陀螺仪MinX
        /// </summary>
        public double GyroscopeMinX
        {
            get => _gyroscopeMinX;
            set => Set(nameof(GyroscopeMinX), ref _gyroscopeMinX, value);
        }

        /// <summary>
        /// 陀螺仪MinX
        /// </summary>
        private double _gyroscopeMinX;

        /// <summary>
        /// 陀螺仪MaxX
        /// </summary>
        public double GyroscopeMaxX
        {
            get => _gyroscopeMaxX;
            set => Set(nameof(GyroscopeMaxX), ref _gyroscopeMaxX, value);
        }

        /// <summary>
        /// 陀螺仪MaxX
        /// </summary>
        private double _gyroscopeMaxX;

        /// <summary>
        /// 陀螺仪Y
        /// </summary>
        public double GyroscopeY
        {
            get => _gyroscopeY;
            set => Set(nameof(GyroscopeY), ref _gyroscopeY, value);
        }

        /// <summary>
        /// 陀螺仪Y
        /// </summary>
        private double _gyroscopeY;

        /// <summary>
        /// 陀螺仪MinY
        /// </summary>
        public double GyroscopeMinY
        {
            get => _gyroscopeMinY;
            set => Set(nameof(GyroscopeMinY), ref _gyroscopeMinY, value);
        }

        /// <summary>
        /// 陀螺仪MinY
        /// </summary>
        private double _gyroscopeMinY;

        /// <summary>
        /// 陀螺仪MaxY
        /// </summary>
        public double GyroscopeMaxY
        {
            get => _gyroscopeMaxY;
            set => Set(nameof(GyroscopeMaxY), ref _gyroscopeMaxY, value);
        }

        /// <summary>
        /// 陀螺仪MaxY
        /// </summary>
        private double _gyroscopeMaxY;

        /// <summary>
        /// 陀螺仪Z
        /// </summary>
        public double GyroscopeZ
        {
            get => _gyroscopeZ;
            set => Set(nameof(GyroscopeZ), ref _gyroscopeZ, value);
        }

        /// <summary>
        /// 陀螺仪Z
        /// </summary>
        private double _gyroscopeZ;

        /// <summary>
        /// 陀螺仪MinZ
        /// </summary>
        public double GyroscopeMinZ
        {
            get => _gyroscopeMinZ;
            set => Set(nameof(GyroscopeMinZ), ref _gyroscopeMinZ, value);
        }

        /// <summary>
        /// 陀螺仪MinZ
        /// </summary>
        private double _gyroscopeMinZ;

        /// <summary>
        /// 陀螺仪MaxZ
        /// </summary>
        public double GyroscopeMaxZ
        {
            get => _gyroscopeMaxZ;
            set => Set(nameof(GyroscopeMaxZ), ref _gyroscopeMaxZ, value);
        }

        /// <summary>
        /// 陀螺仪MaxZ
        /// </summary>
        private double _gyroscopeMaxZ;

        /// <summary>
        /// 抖动
        /// </summary>
        public bool Shake {
            get => _shake;
            set => Set(nameof(Shake), ref _shake, value);
        }

        /// <summary>
        /// 抖动
        /// </summary>
        private bool _shake;

        // ******** 绑定命令

        /// <summary>
        /// 清空所有的数值
        /// </summary>
        private RelayCommand _clear;

        /// <summary>
        /// 清空所有的数值
        /// </summary>
        public RelayCommand Clear =>
            _clear ?? (_clear = new RelayCommand(async () => await ClearFunction()));

        public async Task ClearFunction() {
            AccelerometerX = 0;
            AccelerometerMaxX = 0;
            AccelerometerMinX = 0;
            AccelerometerY = 0;
            AccelerometerMinY = 0;
            AccelerometerMaxY = 0;
            AccelerometerZ = 0;
            AccelerometerMinZ = 0;
            AccelerometerMaxZ = 0;
            GyroscopeX = 0;
            GyroscopeMinX = 0;
            GyroscopeMaxX = 0;
            GyroscopeY = 0;
            GyroscopeMinY = 0;
            GyroscopeMaxY = 0;
            GyroscopeZ = 0;
            GyroscopeMinZ = 0;
            GyroscopeMaxZ = 0;

        }

        /// <summary>
        /// 开始加速计
        /// </summary>
        private RelayCommand _startAccelerometer;

        /// <summary>
        /// 开始加速计
        /// </summary>
        public RelayCommand StartAccelerometer =>
            _startAccelerometer ?? (_startAccelerometer = new RelayCommand(async () => await StartAccelerometerFunction()));

        public async Task StartAccelerometerFunction() {
            if (Accelerometer.IsMonitoring)
                return;
            Accelerometer.ReadingChanged += Accelerometer_ReadingChanged;
            Accelerometer.Start(SensorSpeed.UI);
        }

        /// <summary>
        /// 结束加速计
        /// </summary>
        private RelayCommand _endAccelerometer;

        /// <summary>
        /// 结束加速计
        /// </summary>
        public RelayCommand EndAccelerometer =>
            _endAccelerometer ?? (_endAccelerometer = new RelayCommand(async () => await EndAccelerometerFunction()));

        public async Task EndAccelerometerFunction() {
            if (!Accelerometer.IsMonitoring)
                return;
            Accelerometer.ReadingChanged -= Accelerometer_ReadingChanged;
            Accelerometer.Stop();
        }

        /// <summary>
        /// 开始陀螺仪
        /// </summary>
        private RelayCommand _startGyroscope;

        /// <summary>
        /// 开始陀螺仪
        /// </summary>
        public RelayCommand StartGyroscope =>
            _startGyroscope ?? (_startGyroscope =
                new RelayCommand(async () => await StartGyroscopeFunction()));

        public async Task StartGyroscopeFunction() {
            if (Gyroscope.IsMonitoring)
                return;
            Gyroscope.ReadingChanged += Gyroscope_ReadingChanged;
            Gyroscope.Start(SensorSpeed.UI);
        }

        /// <summary>
        /// 结束陀螺仪
        /// </summary>
        private RelayCommand _endGyroscope;

        /// <summary>
        /// 结束陀螺仪
        /// </summary>
        public RelayCommand EndGyroscope =>
            _endGyroscope ?? (_endGyroscope = new RelayCommand(async () => await EndGyroscopeFunction()));

        public async Task EndGyroscopeFunction() {
            if (!Gyroscope.IsMonitoring)
                return;
            Gyroscope.ReadingChanged -= Gyroscope_ReadingChanged;
            Gyroscope.Stop();
        }

        /// <summary>
        /// 开始检测抖动
        /// </summary>
        private RelayCommand _startDetecteShake;

        /// <summary>
        /// 开始检测抖动
        /// </summary>
        public RelayCommand StartDetecteShake =>
            _startDetecteShake ?? (_startDetecteShake = new RelayCommand(async () => await StartDetecteShakeFunction()));

        public async Task StartDetecteShakeFunction() {
            if (Accelerometer.IsMonitoring)
                return;
            Accelerometer.ShakeDetected += Accelerometer_ShakeDetected;
            Accelerometer.Start(SensorSpeed.UI);
        }

        /// <summary>
        /// 结束检测抖动
        /// </summary>
        private RelayCommand _endDetecteShake;

        /// <summary>
        /// 结束检测抖动
        /// </summary>
        public RelayCommand EndDetecteShake =>
            _endDetecteShake ?? (_endDetecteShake = new RelayCommand(async () => await EndDetecteShakeFunction()));

        public async Task EndDetecteShakeFunction() {
            if (!Accelerometer.IsMonitoring)
                return;
            Accelerometer.ReadingChanged -= Accelerometer_ShakeDetected;
            Accelerometer.Stop();
            Shake = false;
        }

        /// <summary>
        /// 震动
        /// </summary>
        private RelayCommand _vibrate;

        /// <summary>
        /// 震动
        /// </summary>
        public RelayCommand Vibrate =>
            _vibrate ?? (_vibrate = new RelayCommand(async () => await VibrateFunction()));

        public async Task VibrateFunction() {
            try
            {
                // Use default vibration length
                Vibration.Vibrate();
            }
            catch (FeatureNotSupportedException ex)
            {
                // Feature not supported on device
            }
            catch (Exception ex)
            {
                // Other error has occurred.
            }
        }

        /// <summary>
        /// 震动5秒
        /// </summary>
        private RelayCommand _vibrate5Seconds;

        /// <summary>
        /// 震动5秒
        /// </summary>
        public RelayCommand Vibrate5Seconds =>
            _vibrate5Seconds ?? (_vibrate5Seconds = new RelayCommand(async () => await Vibrate5SecondsFunction()));

        public async Task Vibrate5SecondsFunction() {
            try
            {
                // Or use specified time
                var duration = TimeSpan.FromSeconds(5);
                Vibration.Vibrate(duration);
            }
            catch (FeatureNotSupportedException ex)
            {
                // Feature not supported on device
            }
            catch (Exception ex)
            {
                // Other error has occurred.
            }
        }

        /// <summary>
        /// 取消震动
        /// </summary>
        private RelayCommand _cancelVibrate;

        /// <summary>
        /// 取消震动
        /// </summary>
        public RelayCommand CancelVibrate =>
            _cancelVibrate ?? (_cancelVibrate = new RelayCommand(async () => await CancelVibrateFunction()));

        public async Task CancelVibrateFunction() {
            try
            {
                Vibration.Cancel();
            }
            catch (FeatureNotSupportedException ex)
            {
                // Feature not supported on device
            }
            catch (Exception ex)
            {
                // Other error has occurred.
            }
        }


        /// <summary>
        /// 点击触觉反馈
        /// </summary>
        private RelayCommand _clickHapticFeedback;

        /// <summary>
        /// 点击触觉反馈
        /// </summary>
        public RelayCommand ClickHapticFeedback =>
            _clickHapticFeedback ?? (_clickHapticFeedback = new RelayCommand(async () => await ClickHapticFeedbackFunction()));

        public async Task ClickHapticFeedbackFunction() {
            try
            {
                // Perform click feedback
                HapticFeedback.Perform(HapticFeedbackType.Click);
            }
            catch (FeatureNotSupportedException ex)
            {
                // Feature not supported on device
            }
            catch (Exception ex)
            {
                // Other error has occurred.
            }
        }

        /// <summary>
        /// 长按触觉反馈
        /// </summary>
        private RelayCommand _longPressHapticFeedback;

        /// <summary>
        /// 长按触觉反馈
        /// </summary>
        public RelayCommand LongPressHapticFeedback =>
            _longPressHapticFeedback ?? (_longPressHapticFeedback = new RelayCommand(async () => await LongPressHapticFeedbackFunction()));

        public async Task LongPressHapticFeedbackFunction() {
            try
            {
                // Or use long press    
                HapticFeedback.Perform(HapticFeedbackType.LongPress);
            }
            catch (FeatureNotSupportedException ex)
            {
                // Feature not supported on device
            }
            catch (Exception ex)
            {
                // Other error has occurred.
            }
        }

        // ******** 公开变量

        // ******** 私有变量

        // ******** 公开方法

        // ******** 私有方法
        void Accelerometer_ReadingChanged(object sender, AccelerometerChangedEventArgs e)
        {
            var data = e.Reading;
            Console.WriteLine($"Reading: X: {data.Acceleration.X}, Y: {data.Acceleration.Y}, Z: {data.Acceleration.Z}");
            // Process Acceleration X, Y, and Z
            AccelerometerX = data.Acceleration.X;
            if (data.Acceleration.X < AccelerometerMinX)
                AccelerometerMinX = data.Acceleration.X;
            if (data.Acceleration.X > AccelerometerMaxX)
                AccelerometerMaxX = data.Acceleration.X;

            AccelerometerY = data.Acceleration.Y;
            if (data.Acceleration.Y < AccelerometerMinY)
                AccelerometerMinY = data.Acceleration.Y;
            if (data.Acceleration.Y > AccelerometerMaxY)
                AccelerometerMaxY = data.Acceleration.Y;

            AccelerometerZ = data.Acceleration.Z;
            if (data.Acceleration.Z < AccelerometerMinZ)
                AccelerometerMinZ = data.Acceleration.Z;
            if (data.Acceleration.Z > AccelerometerMaxZ)
                AccelerometerMaxZ = data.Acceleration.Z;
        }

        void Gyroscope_ReadingChanged(object sender,
            GyroscopeChangedEventArgs e) {
            var data = e.Reading;
            Console.WriteLine(
                $"Reading: X: {data.AngularVelocity.X}, Y: {data.AngularVelocity.Y}, Z: {data.AngularVelocity.Z}");
            // Process Angular Velocity X, Y, and Z reported in rad/s
            GyroscopeX = data.AngularVelocity.X;
            if (data.AngularVelocity.X < GyroscopeMinX)
                GyroscopeMinX = data.AngularVelocity.X;
            if (data.AngularVelocity.X > GyroscopeMaxX)
                GyroscopeMaxX = data.AngularVelocity.X;

            GyroscopeY = data.AngularVelocity.Y;
            if (data.AngularVelocity.Y < GyroscopeMinY)
                GyroscopeMinY = data.AngularVelocity.Y;
            if (data.AngularVelocity.Y > GyroscopeMaxY)
                GyroscopeMaxY = data.AngularVelocity.Y;

            GyroscopeZ = data.AngularVelocity.Z;
            if (data.AngularVelocity.Z < GyroscopeMinZ)
                GyroscopeMinZ = data.AngularVelocity.Z;
            if (data.AngularVelocity.Z > GyroscopeMaxZ)
                GyroscopeMaxZ = data.AngularVelocity.Z;
        }

        void Accelerometer_ShakeDetected(object sender, EventArgs e)
        {
            // Process shake event
            Shake = true;
        }
    }
}